package com.spzx.product;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.spzx.common.security.annotation.EnableCustomConfig;
import com.spzx.common.security.annotation.EnableRyFeignClients;
import com.spzx.product.domain.ProductSku;
import com.spzx.product.mapper.ProductSkuMapper;
import com.spzx.product.service.IProductSkuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.List;

/**
 * 商品模块
 *
 * @author spzx
 */
@Slf4j
@EnableCustomConfig
@EnableRyFeignClients
@SpringBootApplication
public class SpzxProductApplication implements CommandLineRunner
{
    @Autowired
    private RedisTemplate redisTemplate; //用于从product_sku表中获取sku_id集合，通过Bitmap添加到其中
    @Autowired
    private ProductSkuMapper skuMapper;//用于查询出sku_id集合
    public static void main(String[] args)
    {
        SpringApplication.run(SpzxProductApplication.class, args);
        System.out.println("(♥◠‿◠)ﾉﾞ  系统模块启动成功   ლ(´ڡ`ლ)ﾞ  \n" +
                " .-------.       ____     __        \n" +
                " |  _ _   \\      \\   \\   /  /    \n" +
                " | ( ' )  |       \\  _. /  '       \n" +
                " |(_ o _) /        _( )_ .'         \n" +
                " | (_,_).' __  ___(_ o _)'          \n" +
                " |  |\\ \\  |  ||   |(_,_)'         \n" +
                " |  | \\ `'   /|   `-'  /           \n" +
                " |  |  \\    /  \\      /           \n" +
                " ''-'   `'-'    `-..-'              ");
    }

    /**
     * 此处的作用：
     * 这里引入Redis的BitMap来解决缓存穿透的问题
     * 核心思想及步骤：
     *      1.在启动类中实现CommandLineRunner接口，重写run方法，在项目启动的时候，执行run方法
     *        我们通过这个run方法，提前在项目中就获取skuId集合，并且遍历集合，将每一个skuId存储到
     *        redis的Bitmap中。
     *      2.Redis的Bitmap主要分为3个部分：1.键名 2.偏移量 3.值
     *        我们让key固定为product:sku:data，偏移量即skuId，值为true
     *        值为true的时候代表当前skuId是存在的，值为false的时候代表当前skuId不存在
     *      3.当我们查询商品详情页面的时候，先去Bitmap中查询对应偏移量的值是否为true
     *        若为true，就代表这个skuId是存在的，那么就允许进行访问，否则就直接返回不存在当前商品
     *      4.最后还有在商品的上下架的逻辑中，我们只需要将商品下架的时候，将对应的skuId从从Bitmap中设置值为false
     *      5.还有新增商品的时候，我们不需要担心要先去加skuId，因为默认新增商品的时候，商品的状态是0，
     *        我们需要手动设置上下架的时候，就可以让skuId添加进Bitmap或删除了
     *      6.通过这样子的业务逻辑，我们就解决了【缓存穿透】的问题，
     *        因为我们避免了用户使用不存在的请求数据向服务器频繁发送请求，导致请求越过缓存，导致数据库的IO压力过载
     *        导致的【缓存穿透】
     * @param args
     * @throws Exception
     */
    @Override
    public void run(String... args) throws Exception {
        //定义skuId的键名
        String key = "product:sku:data";
        //只获取状态为上架状态，并且只获取sku_id值
        LambdaQueryWrapper<ProductSku> queryWrapper = new LambdaQueryWrapper<ProductSku>()
                .eq(ProductSku::getStatus, 1)
                .select(ProductSku::getId);
        List<ProductSku> productSkuList = skuMapper.selectList(queryWrapper);
        log.info("获取到对应的sku_id集合，添加到Bitmap中......");
        //遍历集合，将每一个sku对象的id值添加到redis的Bitmap中
        for (ProductSku productSku : productSkuList) {
            Long skuId = productSku.getId();
            log.info("添加skuId：{}到Bitmap中",skuId);
            redisTemplate.opsForValue().setBit(key,skuId,true);
        }
    }
}